
package com.shop.cereshop.admin.service.wallet.impl;

import cn.hutool.core.date.DateUtil;
import com.shop.cereshop.admin.dao.wallet.WalletTransactionDAO;
import com.shop.cereshop.admin.param.wallet.WalletParam;
import com.shop.cereshop.commons.constant.CoReturnFormat;
import com.shop.cereshop.commons.domain.wallet.CereBuyerWallet;
import com.shop.cereshop.commons.domain.wallet.WalletTransaction;
import com.shop.cereshop.admin.service.wallet.WalletTransactionService;

import com.shop.cereshop.commons.exception.CoBusinessException;
import com.shop.cereshop.commons.utils.TimeUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Instant;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 业务实现类
 * 钱包流水表
 * </p>
 *
 * @author wang.yao
 * @date 2025-08-26
 */
@Slf4j
@Service
@AllArgsConstructor
public class WalletTransactionServiceImpl implements WalletTransactionService {

    private final WalletTransactionDAO walletTransactionDAO;

    private final RedissonClient redissonClient;

    @Override
    @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = {CoBusinessException.class, Exception.class})
    public void freezedWallet(WalletParam param) throws CoBusinessException {
        String lockKey = "wallet_freeze:" + param.getBuyerUserId();
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取锁，超时时间10秒，锁定时间30秒
            if (!lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                log.warn("获取分布式锁超时，可能有其他线程正在处理该交易: buyerUserId={}", param.getBuyerUserId());
                throw new CoBusinessException(CoReturnFormat.FAIL);
            }
            // 判断冻结还是解冻操作
            if (param.getActionType() == 1) {
                // 解冻操作
                // 先检查是否已经解冻过
                if (walletTransactionDAO.checkUnFreezeStatus(param.getBuyerUserId()) == 0) {
                    log.info("交易已解冻，无需重复操作: buyerUserId={}", param.getBuyerUserId());
                    return;
                }

                int cancelRows = walletTransactionDAO.cancelFreezedWallet(param);
                if (cancelRows > 0) {
                    log.info("取消冻结成功: buyerUserId={}", param.getBuyerUserId());
                } else {
                    log.warn("取消冻结失败，请检查数据: buyerUserId={}", param.getBuyerUserId());
                    throw new CoBusinessException(CoReturnFormat.FAIL);
                }
            } else {
                // 冻结操作
                // 参数校验
                if (param.getAmount() == null || param.getAmount().compareTo(BigDecimal.ZERO) <= 0 || param.getExpireTime() <= 0) {
                    log.warn("参数错误，请检查数据: buyerUserId={}", param.getBuyerUserId());
                    throw new CoBusinessException(CoReturnFormat.PARAM_INVALID);
                }

                param.setExpireDateTime(TimeUtils.timestampToString(param.getExpireTime()));

                // 先检查是否已经冻结过
                if (walletTransactionDAO.checkFreezeStatus(param.getBuyerUserId()) > 0) {
                    log.info("用户已冻结，无需重复操作: buyerUserId={}", param.getBuyerUserId());
                    return;
                }

                int freezedRows = walletTransactionDAO.freezedWallet(param);
                if (freezedRows > 0) {
                    log.info("冻结成功: buyerUserId={}", param.getBuyerUserId());
                } else {
                    log.warn("冻结失败，请检查数据: buyerUserId={}", param.getBuyerUserId());
                    throw new CoBusinessException(CoReturnFormat.WALLET_BALANCE_ZERO);
                }
            }
        } catch (InterruptedException e) {
            log.error("获取分布式锁时被中断: buyerUserId={}", param.getBuyerUserId(), e);
            Thread.currentThread().interrupt();
            throw new CoBusinessException(CoReturnFormat.FAIL);
        } catch (CoBusinessException e) {
            // 直接重新抛出业务异常
            throw e;
        } catch (Exception e) {
            log.error("处理冻结/解冻操作时发生异常: buyerUserId={}", param.getBuyerUserId(), e);
            throw new CoBusinessException(CoReturnFormat.FAIL);
        } finally {
            // 确保释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public List<CereBuyerWallet> findExpiredFreeze(String now, int pageSize, Long lastId) {
        return walletTransactionDAO.findExpiredFreeze(now, pageSize, lastId);
    }

    @Override
    @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = {CoBusinessException.class, Exception.class})
    public int batchUnfreeze(List<Long> walletIds) {
         return walletTransactionDAO.batchUnfreeze(walletIds);
    }
}
